package de.bib.blue.manage.finance.view;

import java.util.Date;
import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.experimental.chart.swt.ChartComposite;

import de.bib.blue.manage.finance.Activator;
import de.bib.blue.manage.finance.database.ResourceDatabase;
import de.bib.blue.manage.finance.dialog.BarDialog;
import de.bib.blue.manage.finance.dialog.SearchDialog;
import de.bib.blue.manage.finance.jfree.PieChartComposite;
import de.bib.blue.manage.finance.jfree.TimeLineChart;
import de.bib.blue.manage.finance.parser.LoadFile;
import de.bib.blue.manage.finance.util.UIHelper;

public class MonitorView extends ViewPart {

	public static final String ID = "de.bib.blue.manage.finance.view.MonitorView";

	public static final String VERSION = "1.0.0";
	public static final String TITLE = "FINANCE MONITORING";
	protected static final String SUMMARY_TOTAL_PENGELUARAN = "Total Pengeluaran";
	protected static final String PERCENTAGE_PENGELUARAN = "Percentage Pengeluaran";
	protected static final String DETAIL_PENGELUARAN = "Detail Pengeluaran";
	private static final String TOTAL = "Total Pengeluaran";
	private static final String BULAN = "Bulan";

	public static final String SAVE_LINE_CHART = "de.bib.blue.manage.finance.command.SaveLineChartCommand";
	public static final String SAVE_PIE_CHART = "de.bib.blue.manage.finance.command.SavePieChartCommand";
	public static final String SEARCH = "de.bib.blue.manage.finance.command.SearchCommand";
	public static final String BARCHART = "de.bib.blue.manage.finance.command.BarChartCommand";

	protected FormToolkit toolkit = null;
	protected ScrolledForm form;
	private Composite body;
	private Composite panel = null;
	private SashForm vertical;
	private SashForm horizontal;

	private Table detailTable;
	private TimeLineChart chart;
	private PieChartComposite pie;

	private ResourceDatabase db = null;

	private boolean cekSrc = false;
	private Date d = null;
	private String[] si = null;
	private String refDate = "";

	private RefreshJob job;
	private static final long DELAY = 10 * 1000;

	@Override
	public void createPartControl(Composite parent) {
		try {
			db = ResourceDatabase.getInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		createForm(parent, TITLE);
		createToolbar();
		createBody();

		// buat schedule untuk refresh dashboard
		job = new RefreshJob();
		job.setSystem(true);
		job.setPriority(RefreshJob.DECORATE);
		job.schedule(DELAY);
	}

	protected void createForm(Composite parent, String title) {
		toolkit = new FormToolkit(parent.getDisplay());
		form = toolkit.createScrolledForm(parent);
		toolkit.decorateFormHeading(form.getForm());
		form.setText(title);

		form.getBody().setLayoutData(UIHelper.fillBoth());
		form.getBody().setLayout(new FillLayout());
	}

	protected void createToolbar() {
		ToolBarManager manager = (ToolBarManager) form.getToolBarManager();
		ToolBar toolBar = manager.createControl(form);
		final Cursor handCursor = new Cursor(Display.getCurrent(),
				SWT.CURSOR_HAND);
		toolBar.setCursor(handCursor);

		// Cursor needs to be explicitly disposed
		toolBar.addDisposeListener(new DisposeListener() {
			public void widgetDisposed(DisposeEvent e) {
				if ((handCursor != null) && (handCursor.isDisposed() == false)) {
					handCursor.dispose();
				}
			}
		});

		manager.add(createContribItem(BARCHART, "icons/barchart.jpg",
				"Bar Chart"));
		manager.add(createContribItem(SAVE_LINE_CHART,
				"icons/save_history.gif", "Save Line Chart into Image File"));
		manager.add(createContribItem(SAVE_PIE_CHART, "icons/save_image.gif",
				"Save Pie Chart into Image File"));
		manager.add(createContribItem(SEARCH, "icons/search.gif", "Search Data"));
		manager.update(true);
	}

	private CommandContributionItem createContribItem(String id,
			String imagePath, String tooltip) {
		CommandContributionItemParameter savePar = new CommandContributionItemParameter(
				getSite(), null, id, CommandContributionItem.STYLE_PUSH);
		savePar.icon = Activator.getImageDescriptor(imagePath);
		savePar.tooltip = tooltip;
		CommandContributionItem saveItem = new CommandContributionItem(savePar);
		return saveItem;
	}

	private void createBody() {
		body = new Composite(form.getBody(), SWT.NONE);
		body.setLayout(new FillLayout());

		vertical = new SashForm(body, SWT.VERTICAL);
		createTimeLineChart();

		horizontal = new SashForm(vertical, SWT.HORIZONTAL);
		createDynamicChart();
		createHistoryTable();
		vertical.setWeights(new int[] { 1, 1 });
	}

	private void createTimeLineChart() {
		List<Object[]> results = db.getSummary();

		Section section = createSection(vertical, SUMMARY_TOTAL_PENGELUARAN);
		/*
		 * Buat panel
		 */
		panel = new Composite(section, SWT.BORDER);

		/*
		 * Siapkan layout untuk mengatur panel
		 */
		panel.setLayoutData(new GridData(GridData.FILL_BOTH));
		panel.setLayout(new FillLayout());

		chart = new TimeLineChart(SUMMARY_TOTAL_PENGELUARAN, BULAN, TOTAL);

		addContentChart(results, chart);
		chart.createChart();

		ChartComposite frame = new ChartComposite(panel, SWT.NONE,
				chart.getChart(), true);
		frame.setDisplayToolTips(true);
		frame.setHorizontalAxisTrace(false);
		frame.setVerticalAxisTrace(false);

		// untuk tidak menampilkan chart dalam bentuk zoom.
		frame.setRangeZoomable(false);
		frame.setDomainZoomable(false);

		frame.addChartMouseListener(new ChartMouseListener() {
			@Override
			public void chartMouseMoved(ChartMouseEvent event) {
			}

			@Override
			public void chartMouseClicked(ChartMouseEvent event) {
				if (event.getEntity() instanceof XYItemEntity) {
					XYItemEntity entity = (XYItemEntity) event.getEntity();
					if (entity != null) {
						cekSrc = true;

						// indeks dari series yang di-click
						int index = entity.getSeriesIndex();
						// urutan item yang di-click
						int item = entity.getItem();

						TimeSeriesCollection dataset = (TimeSeriesCollection) entity
								.getDataset();

						d = new Date((long) dataset.getXValue(index, item));
						si = String.valueOf(d).split("\\s+");

						/** refresh pie chart. */
						List<Object[]> pieResults = db
								.getPercentageByMonth(si[1]);
						String[] values = new String[pieResults.size()];
						String[] headers = new String[pieResults.size()];
						for (int i = 0; i < pieResults.size(); i++) {
							for (int j = 0; j < pieResults.get(i).length; j++) {
								Object[] fields = pieResults.get(i);

								headers[i] = fields[0].toString();
								values[i] = fields[1].toString();
							}
						}
						pie.refresh(values, headers);

						/** refresh detail table. */
						detailTable.removeAll();
						List<Object[]> detailResults = db
								.getDetailByMonth(si[1]);
						createDetailContents(detailResults);
						detailTable.layout();

						refDate = si[1];

					}
				}
			}

		});

		section.setClient(panel);
	}

	private void addContentChart(List<Object[]> results, TimeLineChart chart) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("MMMyy");

		String label = "Total_Pengeluaran";
		LinkedList<Date> date = new LinkedList<Date>();
		LinkedList<Number> values = new LinkedList<Number>();

		int start = 0;
		for (int i = start; i < results.size(); i++) {
			Object[] fields = results.get(i);
			Date refDate = null;
			try {
				refDate = dateFormat.parse(fields[0].toString());
			} catch (ParseException e) {
				e.printStackTrace();
			}
			Number number = (Number) fields[1];

			date.add(refDate);
			values.add(number);
		}
		chart.addTimeSeries(label, date, values);
	}

	private void createDynamicChart() {
		List<Object[]> results = db.getPercentageByFirstMonth();
		String[] values = new String[results.size()];
		String[] headers = new String[results.size()];
		for (int i = 0; i < results.size(); i++) {
			for (int j = 0; j < results.get(i).length; j++) {
				Object[] fields = results.get(i);

				headers[i] = fields[0].toString();
				values[i] = fields[1].toString();
			}
		}

		Section section = createSection(horizontal, PERCENTAGE_PENGELUARAN);
		pie = new PieChartComposite(section, PERCENTAGE_PENGELUARAN, headers);

		pie.createChart(values);
		section.setClient(pie.getComposite());
	}

	private void createHistoryTable() {
		detailTable = createTable(horizontal, "Detail Pengeluaran");
		createColumns(detailTable);

		List<Object[]> results = db.getDetailByFirstMonth();
		createDetailContents(results);
	}

	private void createDetailContents(List<Object[]> results) {
		Integer count = 1;
		LinkedList<String[]> contents = new LinkedList<String[]>();

		String[] values = null;
		for (int i = 0; i < results.size(); i++) {
			values = new String[6];
			Object[] fields = results.get(i);
			for (int j = 0; j < fields.length; j++) {
				values[j + 1] = fields[j].toString();
			}
			values[0] = count.toString();
			contents.add(values);
			count++;
		}
		addDetailTableValues(contents);

	}

	private void addDetailTableValues(LinkedList<String[]> contents) {
		for (String[] values : contents) {
			TableItem newItem = new TableItem(detailTable, SWT.None);
			newItem.setText(values);
		}
	}

	private void createColumns(Table table) {
		createColumn(table, "No", 30);
		createColumn(table, "Tgl", 100);
		createColumn(table, "Bulan", 50);
		createColumn(table, "Kode", 40);
		createColumn(table, "Pengeluaran", 150);
		createColumn(table, "Ket", 250);
	}

	protected void createColumn(Table table, String label, int width) {
		UIHelper.createColumn(table, label, width);
	}

	protected Table createTable(Composite parent, String sectionTitle) {
		Section section = createSection(parent, sectionTitle);

		Composite tabelPanel = toolkit.createComposite(section);
		tabelPanel.setLayout(new FillLayout());

		Table table = toolkit.createTable(tabelPanel, SWT.VIRTUAL
				| SWT.FULL_SELECTION | SWT.MULTI | SWT.V_SCROLL);
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		section.setClient(tabelPanel);
		return table;
	}

	protected Section createSection(Composite parent, String title) {
		Section section = toolkit.createSection(parent, Section.TITLE_BAR);
		section.setText(title);
		return section;
	}

	@Override
	public void setFocus() {
	}

	public TimeLineChart getChart() {
		return chart;
	}

	@Override
	public void dispose() {
		toolkit.dispose();
		super.dispose();
	}

	public void savePieChart() {
		String label = "Save Pie Chart";
		Shell shell = getSite().getShell();
		FileDialog fileDialog = createFileDialog(label, shell, "*.png", "*.jpg");
		String filename = fileDialog.open();
		if (filename == null) {
			return;
		}

		try {
			if (filename.endsWith(".png")) {
				pie.getChart().saveChartIntoPNG(filename);
			} else if (filename.endsWith(".jpg")) {
				pie.getChart().saveChartIntoJPEG(filename);
			}
		} catch (Exception e) {
			String message = "Fail save chart into " + filename;
			MessageDialog.openError(shell, label, message);
		}

	}

	public void saveLineChart() {
		String label = "Save Line Chart";
		Shell shell = getSite().getShell();
		FileDialog fileDialog = createFileDialog(label, shell, "*.png", "*.jpg");
		String filename = fileDialog.open();
		if (filename == null) {
			return;
		}

		try {
			if (filename.endsWith(".png")) {
				chart.saveChartIntoPNG(filename);
			} else if (filename.endsWith(".jpg")) {
				chart.saveChartIntoJPEG(filename);
			}
		} catch (Exception e) {
			String message = "Fail save chart into " + filename;
			MessageDialog.openError(shell, label, message);
		}

	}

	public void search() {
		String date = "Jan";
		if (refDate.length() > 0) {
			date = refDate;
		}

		Shell shell = getSite().getShell();
		SearchDialog sd = new SearchDialog(shell);
		if (sd.open() == SearchDialog.OK) {
			String param = " " + sd.getFields() + " " + sd.getOperands() + " '"
					+ sd.getValue() + "' AND Bulan_Transaksi Like '" + date
					+ "%'";

			/** refresh detail table. */
			detailTable.removeAll();
			List<Object[]> detailResults = db.getDetailBySearch(param);
			createDetailContents(detailResults);
			detailTable.layout();

		}
	}

	private FileDialog createFileDialog(String label, Shell shell,
			String... filters) {
		FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
		fileDialog.setText(label);
		fileDialog.setFilterPath("C:/");
		fileDialog.setFilterExtensions(filters);
		return fileDialog;
	}

	public void barChart() {

		String bln = "";
		String[] headers = null;
		String[] values = null;

		if (cekSrc) {
			si = String.valueOf(d).split("\\s+");

			/** refresh pie chart. */
			List<Object[]> pieResults = db.getPercentageByMonth(si[1]);
			values = new String[pieResults.size()];
			headers = new String[pieResults.size()];
			for (int i = 0; i < pieResults.size(); i++) {
				for (int j = 0; j < pieResults.get(i).length; j++) {
					Object[] fields = pieResults.get(i);

					headers[i] = fields[0].toString();
					values[i] = fields[1].toString();
				}
			}

			bln = si[1];

		} else {
			List<Object[]> results = db.getPercentageByFirstMonth();
			values = new String[results.size()];
			headers = new String[results.size()];
			for (int i = 0; i < results.size(); i++) {
				for (int j = 0; j < results.get(i).length; j++) {
					Object[] fields = results.get(i);

					headers[i] = fields[0].toString();
					values[i] = fields[1].toString();
				}
			}

			bln = "Jan";
		}
		Shell shell = getSite().getShell();
		
		BarDialog bd = new BarDialog(shell, headers, values, bln);
		bd.open();
	}

	/**
	 * Job untuk refresh data terakhir.
	 * 
	 * @author eko wahyud
	 * 
	 */
	private class RefreshJob extends UIJob {

		/**
		 * Default kontruktor.
		 */
		public RefreshJob() {
			super("Refresh Job for Last Data");
		}

		@Override
		public IStatus runInUIThread(IProgressMonitor monitor) {
			monitor.beginTask("Refreshing last data", IProgressMonitor.UNKNOWN);
			refresh();
			job.schedule(DELAY);
			return Status.OK_STATUS;
		}

	}

	public void refresh() {
		refreshCharts();
		panel.layout();

	}

	private void refreshCharts() {
		List<Object[]> results = db.getSummary();
		LoadFile f = new LoadFile(db);
		try {
			f.loadsFile();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}

		chart.clearData();
		addContentChart(results, chart);

	}

}
